package com.cy.pj.sys.service.aspect;

import com.cy.pj.sys.pojo.SysLog;
import com.cy.pj.sys.pojo.common.annotation.RequiredLog;
import com.cy.pj.sys.service.SysLogService;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.Date;


/**
 * Spring AOP中，基于@Aspect注解描述的类型为切面类型，该类封装切入点击通知方法的定义
 */
@Order(2)
@Slf4j
@Aspect
@Component
public class SysLogAspect {

    //private static final Logger log = LoggerFactory.getLogger(SysLogAspect.class);

    @Pointcut("@annotation(com.cy.pj.sys.pojo.common.annotation.RequiredLog)")
    public void doLog(){}

    @Around("doLog()")
    public Object doAround(ProceedingJoinPoint jp)throws Throwable{
        long t1=System.currentTimeMillis();
        log.info("method start {}",t1);
        try {
            //执行调用目标方法
            Object result =  jp.proceed();
            long t2=System.currentTimeMillis();
            log.info("method after {}",t2);
            doSaveLogInfo(jp,(t2-t1),null);
            return result;
        }catch (Throwable e){
            log.info("method error {}",System.currentTimeMillis());
            long t3=System.currentTimeMillis();
            doSaveLogInfo(jp,(t3-t1),e);
            throw e;
        }
    }

    @Autowired
    private SysLogService sysLogService;
    private void doSaveLogInfo(ProceedingJoinPoint jp,long time,Throwable e) throws NoSuchMethodException, JsonProcessingException {


        String username="Tom";
        String ip="192.168.1.1";
        Class<?> cls=jp.getTarget().getClass();
        Signature signature= jp.getSignature();
        MethodSignature methodSignature= (MethodSignature) signature;
        Method targetMethod=
                cls.getDeclaredMethod(methodSignature.getName(), methodSignature.getParameterTypes());
        RequiredLog requiredLog = targetMethod.getAnnotation(RequiredLog.class);

        String operation=requiredLog.operation();
        String method=cls.getName()+"."+targetMethod.getName();
        Object[]args=jp.getArgs();
        String params=new ObjectMapper().writeValueAsString(args);
        Integer status=e==null?1:0;
        String error=e==null?"":e.getMessage();

        SysLog sysLog = new SysLog();
        sysLog.setUsername(username);
        sysLog.setIp(ip);
        sysLog.setCreatedTime(new Date());
        sysLog.setOperation(operation);
        sysLog.setMethod(method);
        sysLog.setParams(params);
        sysLog.setStatus(status);
        sysLog.setError(error);
        sysLog.setTime(time);

        log.info("user log {}",new ObjectMapper().writeValueAsString(sysLog));
        sysLogService.saveLog(sysLog);
    }
}
